-
Notifications
You must be signed in to change notification settings - Fork 77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for procs and method calls in inclusion validation dropdown resolution #1040
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing, thank you! 🎉
Few comments but not a blocker to merge
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we want this. We're doing a best effort job of showing possible values when the inclusion validator is simple enough, but we shouldn't go and call random code, this is called in a view after all.
We have a way to extend the form by adding a maintenance_tasks/tasks/custom
partial in the application. (It's not documented BTW sorry). I guess you could use this to conditionally add fields, hide the previous fields for an attribute, if you wanted to go down that route.
I think it's problematic that some validations can now break your views or make choices inaccessible. There should be some kind of opt-in at the very least.
Or maybe it's just not something that should be done in the engine. We do mention "Normally maintenance tasks are ephemeral, so they are used briefly and then deleted." in the README. The initial use case of wanting to list the application records feels like something that might be built in the application directly instead in some kind of admin interface, if it needs to access any and all models at any time.
https://github.com/Shopify/maintenance_tasks#should-i-use-maintenance-tasks
Otherwise one can always do Rails.application.eager_load!; ActiveRecord::Base.descendants
in a console and stick the result in the validation of the task's param (since the task is temporary, it should be fine). Or just live with the fact that the form will not include a dropdown for the model, the target user for the engine being a developer, they should be able to deal with that situation.
I don't understand this point. I wouldn't qualify this as random code, it's very explicitly the proc to generate the options and it should be fast and reliable, since it's meant to be used in validations.
This seems very convoluted. Using the partial is only really useful to add fields. How would it work to hide previous fields? If we were to say that the standard way of customizing fields is through overriding, we should make it easy in the gem, by making a dedicated
I don't understand this point. What would break? Are you referring to when it has more than 1000 items? If so, I replied elsewhere.
As a compromise, I would be ok with a
I would argue that just because the gem is not intended for permanent tasks isn't a reason to not support making that a viable option.
We have cases with ~100 classes to pick from. This quickly becomes noise, a maintenance nightmare, or an annoyance.
This increases the chances of errors. 👉🏼 I think my most important point is that ActiveModel is designed to support dynamic inclusion constraints, but this gem decided to opt-out of that support. I understand that stateful constraints can't be supported, but I don't see why we shouldn't support stateless lambdas. |
I think that would be good.
Yes because there are a thousand no's for every yes.
We support it just fine, we're just not making it easy for the user by providing the potential values as a dropdown.
So what are stateful constraints by the way? Lambdas that take the record? Also
I guess they raise more issues, but I wonder why we wouldn't support that as well at this point. Do we need to deal with potential exceptions raised from the lambda? Before we were just getting a value from the task, now we're calling code, so I guess there's more potential for failure here. We should also document the dropdown feature (and the scope of the support for views with this PR) in the README as well. I guess that could be an indicator that the feature is too complex if we need too many words to explain it. Before: "if you have an inclusion validator on your parameter, if the allowed values is a Array, it will be used to build a dropdown". Now we'll need to add some more words. Also just realized that if there's an Interested to hear what @adrianna-chang-shopify and @nvasilevski think. And anyone else actually. |
Yeah, validations are designed to run within the context of the object with the values at the right place, so adding that limitation seems fair to me. If someone wants to call a method, they can do so in a proc: validates :model, inclusion: { in: ->() { MyClass.allowed_model_values } }
Indeed, but if the code is throwing an exception, I think it's perfectly reasonable to let it raise unhandled
Yeah, I can do that once we settle 👍🏼
That's a valid concern, but it's also already true today. I don't think this PR makes the status quo any different. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I somehow missed this when it was initially opened and just spotted it today 😅
Overall, I'm fine with this feature being added. I think it's well scoped and don't feel it encourages or discourages non-ephemeral tasks more than what we already offer in the gem 🤷♀️ IMO if we're confident we can resolve the proc / enumerable to a set of values to populate the dropdown, there's no harm in doing so.
I'd like to see MAX_INCLUSION_ITEMS
made configurable, but I disagree with it defaulting to 0, since this will fully disable the dropdown support we already implemented with arrays, no?
06eb42d
to
e78fe9d
Compare
Done |
e78fe9d
to
0389ff9
Compare
The tests are now failing, but I don't understand why. I don't see what it had to do with my PR 🤔 I rebased. Perhaps I picked up something? |
It's reproducible on |
b9b300c
to
9a3863c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks largely good to 🚢 on my end, other than the two small comments. Let's also add more docs to the README before this is merged. Thanks!
9a3863c
to
02e7e95
Compare
There doesn't seem to be any section in the README that exists where this can fit. I suggest we merge this and tackle documentation separately. |
Adrianna has taken over the review
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think with the benefit of hindsight, I can more clearly see what needs to be done here. The original use case of having a list of models is something that's worth pursuing, however the generalization over all Enumerable doesn't feel useful to me (the developer can just call to_a
in the validation definition: validates_inclusion_of :my_attribute, in: some_enum.to_a
), and the necessity to add a new config option just sucks. We can trust the developer user as long as it's well documented.
And once we support calling a Proc, we might as well support the symbol/method call case, I feel like it's a very common refactoring to go from validates_inclusion_of :my_attribute, in: -> { ApplicationRecord.descendants }
to
validates_inclusion_of :my_attribute, in: :allowed_records
def allowed_records
ApplicationRecord.descendants
end
I suggest we merge this and tackle documentation separately.
Let's not do this.
02e7e95
to
b2bd1b9
Compare
b2bd1b9
to
36bf83c
Compare
Co-authored-by: Sebastien Lavoie <[email protected]>
36bf83c
to
07cc477
Compare
07cc477
to
6207133
Compare
@etiennebarrie fixed to support arity-one procs / lambdas appropriately, and I also tweaked this to support callable objects, since that is supported in the |
6207133
to
8019c1b
Compare
as well as callable objects.
8019c1b
to
2cbb407
Compare
Add support for a few variations of inclusion constraints.
The motivating factor behind this is to be able to resolve to a list of classes that can only be resolved at runtime.
For example, this is not stable, it depends in which order the classes are loaded:
It needs a lambda:
However, stateful lambda are prohibited, because they depend on the task instance:
While at it, this PR also adds support for bounded enumerables:
See the update test and comments for a full explanation.